#ifndef USB_CAM_H_
#define USB_CAM_H_

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>


#include <string>
#include <memory>

#include "linux/videodev2.h"
#include "utils.hpp"

namespace usb_cam{

typedef struct image_t
{
    char* data;
    size_t width;
    size_t height;
    size_t size_in_bytes;
    size_t framerate;
    double stamp;
    image_t(size_t w, size_t h, size_t f): data(NULL), width(w), height(h), size_in_bytes(w*h*3), framerate(f)
    {

    }
} image_t;

typedef struct parameters_t
{
  std::string device_name;  // 设备名
  std::string io_method_name; // io读取方式
  std::string pixel_format_name; // 图片格式
  int image_width;
  int image_height;
  int framerate;

  //具体参数
  int brightness;
  int contrast;
  int saturation;
  int sharpness;
  int gain;
  int white_balance;
  int exposure;
  int focus;
  bool auto_white_balance;
  bool autoexposure;
  bool autofocus;

  parameters_t()
// *INDENT-OFF*
    : device_name("/dev/video0"),
    io_method_name("mmap"),
    pixel_format_name("yuyv2rgb"),
    image_width(600),
    image_height(480),
    framerate(30.0),
    brightness(-1),
    contrast(-1),
    saturation(-1),
    sharpness(-1),
    gain(-1),
    white_balance(-1),
    exposure(-1),
    focus(-1),
    auto_white_balance(true),
    autoexposure(true),
    autofocus(false)
  {
  }
// *INDENT-ON*
} parameters_t;

class UsbCam
{
public:
    UsbCam(std::string name, size_t w, size_t h, size_t f);
    ~UsbCam();

    void set_exposure(bool flag, int mode, int value){
        m_set_exposure_flag = flag;
        m_exposure_auto = mode;
        m_exposure_absolute = value;

    };

    void configure();

    void start();

    void shutdown();

    // char* get_image();

    void get_image(char * destination);

    inline size_t get_image_size_in_bytes()
    {
        return m_image.size_in_bytes;
    }
    inline size_t get_image_width()
    {
        return m_image.width;
    }

    inline size_t get_image_height()
    {
        return m_image.height;
    }
    inline double get_image_stamp()
    {
        return m_image.stamp;
    }

private:
    int init_device();

    int init_mmap();

    int open_device();

    int grab_image();

    void read_frame();

    void uninit_device();

    int close_device();

    int start_capturing();

    void stop_capturing();

    std::string m_device_name;

    int m_fd;
    unsigned int m_number_of_buffers;
    std::shared_ptr<usb_cam::utils::buffer[]> m_buffers;
    bool m_is_capturing;
    image_t m_image;
    const time_t m_epoch_time_shift_us;
    bool m_set_exposure_flag;
    int m_exposure_auto;
    int m_exposure_absolute;


};

} // namespace usb_cam

#endif // USB_CAM_H__